//--------------------------------------------------------------------------------
// Alec G Thilenius
//
// This software is distributed under the MIT License, available at the following
// URL:
// http://www.opensource.org/licenses/mit-license.php
//--------------------------------------------------------------------------------

#include "Vertex.h"
using namespace AlecThilenius;


//-------------------    Member functions   ---------------------

Vertex::Vertex(std::string name, Graph* graphRef)
{
	m_name = name;
	m_graphRef = graphRef;
}

Vertex::~Vertex(void)
{
}

const std::string& Vertex::GetName() const
{
	return m_name;
}

EdgePtr Vertex::GetEdgeTo( const VertexPtr vertex )
{
	EdgeMapIter iter = m_edgeMap.find(vertex->GetName());

	if ( iter != m_edgeMap.end() )
	{
		return iter->second;
	}

	return m_graphRef->NullEdge;
}

EdgePtr Vertex::CreateEdgeTo( const VertexPtr vertex, double weight )
{
	//Check for self assignment!
	if ( vertex.get() == this )
		return m_graphRef->NullEdge;

	EdgeMapIter iter = m_edgeMap.find(vertex->GetName());

	//Check if the Edge already exists.
	if ( iter != m_edgeMap.end() )
		return m_graphRef->NullEdge;

	// Lock this, save edge, inform other vertex we are referencing
	// them, and return a new EdgePtr
	if ( VertexPtr myPtr = m_sharedResource.lock() )
	{
		EdgePtr newEdgePtr = EdgePtr(new Edge ( vertex, myPtr, weight));
		m_edgeMap.insert(EdgeMap::value_type(vertex->GetName(), newEdgePtr));

		vertex->m_headSet.insert(HeadSet::value_type(m_name, myPtr));

		return newEdgePtr;
	}

	return m_graphRef->NullEdge;
}

const void AlecThilenius::Vertex::GetAllEdges( EdgePtr* edges, int* count )
{
	throw std::exception("Not yet implemented!");
}

double AlecThilenius::Vertex::GetWieghtToVertex( const VertexPtr vertex )
{
	EdgeMapIter iter = m_edgeMap.find(vertex->GetName());

	if ( iter != m_edgeMap.end() )
		return iter->second->GetWeight();

	return -1;
}

void AlecThilenius::Vertex::SetWeightToVertex( const VertexPtr vertex, double weight )
{
	EdgeMapIter iter = m_edgeMap.find(vertex->GetName());

	if ( iter != m_edgeMap.end() )
		iter->second->SetWeight(weight);
}

bool Vertex::RemoveEdgeTo( const VertexPtr vertex )
{
	throw std::exception("Not yet implemented!");
}

void Vertex::RemoveAllEdgeTails()
{
	m_edgeMap.clear();
}

void Vertex::RemoveAllEdges()
{
	//First attain a lock to this
	if ( VertexPtr myPtr = m_sharedResource.lock() )
	{
		m_edgeMap.clear();

		//Remove all heads
		for ( HeadSetIter iter = m_headSet.begin(); iter != m_headSet.end(); ++iter )
			iter->second->m_headSet.erase(m_name);
	}
}

void AlecThilenius::Vertex::Print( std::ostream& oS )
{
	oS << "Vertex: " << m_name << std::endl;

	for ( EdgeMap::const_iterator iter = m_edgeMap.begin(); iter != m_edgeMap.end(); ++iter )
	{
		oS << "- " << iter->first << ", " << iter->second->GetWeight() << std::endl;
	}
}

//Stream Overloads
std::ostream& operator << ( std::ostream& stream, Vertex& vertex )
{
	vertex.Print(stream);
	return stream;
}